package applets;

import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.ScrollPane;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

import wheel.KeyWheel;
import wheel.M209Wheels;
import algorithms.Beaufort;
import algorithms.GetBeaufortKey;
import algorithms.Key;
import algorithms.StringToSetting;
import bar.Bar;
import bar.Lug;
import bar.M209Bars;

public class M209Applet extends Applet implements ActionListener {

    /**
     * serial ID
     */
    private static final long serialVersionUID = -4316982731468739714L;

    
    JButton b1, b2, b3, b4, b5, b6;

    M209Wheels m209wheels = new M209Wheels();
    M209Bars m209Bars = new M209Bars();
    GetBeaufortKey getBeaufortKey = new GetBeaufortKey();
    Beaufort beaufort = new Beaufort();
    StringToSetting stringToSetting = new StringToSetting();

    TextArea parametersInput = new TextArea("", 1, 9, 3);// ("", 33, 26);

    TextField intialKeyInput = new TextField(6);
    TextField externalKeyInput = new TextField(6);
    TextField activeKeyInput = new TextField(6);
    TextField beaufortShitKeyInput = new TextField(2);
    TextField counterInput = new TextField(3);

    TextField plainTextInput = new TextField(30);
    TextField cipherTextInput = new TextField(30);

    Map<KeyWheel, List<ButtonWheel>> keysButtons = new HashMap<KeyWheel, List<ButtonWheel>>();
    Map<Bar, List<JButton>> lugsButtons = new HashMap<Bar, List<JButton>>();

    Button goButton = new Button("Encrypt");
    Button resetButton = new Button("Reset");
    Button modeButton = new Button("Mode: C/D");
    boolean isC = false;

    Button parametersButton = new Button("Set parameters via TextArea");
    int letterCounter = 0;
    int shitCounter = 0;

    Panel configuration = new Panel();
    Panel simulation = new Panel();
    Panel information = new Panel();

    ScrollPane drumSection = new ScrollPane();
    ScrollPane wheelsSection = new ScrollPane();

    // TO VISUALIZE THE SETTINGS
    public final static Color DEFAULT_BG = Color.WHITE;
    public final static Color ACTIVE_BG = Color.PINK;

    // TO VIZUALIZE THE ACTIVE PARTS
    Font fontActive = new Font(Font.MONOSPACED, Font.BOLD, 14);
    Font fontDefault = new Font(Font.MONOSPACED, Font.PLAIN, 12);
    Color DEFAULT_FG = Color.BLACK;
    Color ACTIVE_FG = Color.RED;
    Color ACTIVE_FG2 = Color.BLUE;

    public M209Applet() {
    }

    public void init() {
	setBackground(Color.WHITE);
	int globalWidth = 400;
	int sizeConfiguartion = 150;
	int sizeSimulation = 300;
	int sizeInformation = 60;
	int border = 2;
	int title = 30 + 2 * border;
	// setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
	setLayout(null);
	setSize(globalWidth + 4 * border, sizeConfiguartion + sizeSimulation + sizeInformation + 6 * border + 3 * title);
	System.out.println(getSize());

	Font font = new Font(Font.MONOSPACED, Font.PLAIN, 14);

	JLabel titleLabel = new JLabel("     CONFIGURATION");
	titleLabel.setForeground(Color.LIGHT_GRAY);
	titleLabel.setLocation(0, 2 * border);
	titleLabel.setVerticalAlignment(3);
	titleLabel.setSize(globalWidth + 4 * border, 30);
	add(titleLabel);
	titleLabel = new JLabel("     SIMULATION");
	titleLabel.setForeground(Color.LIGHT_GRAY);
	titleLabel.setVerticalAlignment(3);
	titleLabel.setLocation(0, title + sizeConfiguartion + 3 * border);
	titleLabel.setSize(globalWidth + 4 * border, 30);
	add(titleLabel);
	titleLabel = new JLabel("     INFORMATION");
	titleLabel.setForeground(Color.LIGHT_GRAY);
	titleLabel.setVerticalAlignment(3);
	titleLabel.setLocation(0, 2 * title + sizeConfiguartion + sizeSimulation + 4 * border);
	titleLabel.setSize(globalWidth + 4 * border, 30);
	add(titleLabel);
	// ///////////// CONFIGURATION \\\\\\\\\\\\\\\\\\\\\\\\

	configuration.setLayout(null);
	configuration.setBackground(Color.WHITE);
	configuration.setLocation(2 * border, 2 * border + title);
	configuration.setSize(globalWidth, sizeConfiguartion);
	add(configuration);

	// EXTERNAL KEY
	Panel panel2 = new Panel();
	panel2.setLayout(new FlowLayout());
	panel2.setSize(400, 30);
	panel2.setLocation(0, 0);
	configuration.add(panel2);
	panel2.add(new Label("Initial key"));
	panel2.add(intialKeyInput);
	intialKeyInput.addActionListener(this);
	intialKeyInput.setText("PURPLE");
	intialKeyInput.setFont(font);

	// PLAIN TEXT
	panel2 = new Panel();
	panel2.setSize(400, 30);
	panel2.setLocation(0, 30);
	panel2.setLayout(new FlowLayout());
	configuration.add(panel2);
	panel2.add(new Label("Input text"));
	panel2.add(plainTextInput);
	plainTextInput.setText("HELLO WORLD");
	plainTextInput.setFont(font);

	// CIPHER TEXT
	panel2 = new Panel();
	panel2.setSize(400, 30);
	panel2.setLocation(0, 60);
	panel2.setLayout(new FlowLayout());
	configuration.add(panel2);
	panel2.add(new Label("Output text"));
	panel2.add(cipherTextInput);
	cipherTextInput.setFont(font);
	cipherTextInput.setEditable(false);

	// TextArea Parameters
	panel2 = new Panel();
	panel2.setSize(400, 50);
	panel2.setLocation(0, 90);
	panel2.setLayout(new FlowLayout());
	configuration.add(panel2);
	panel2.add(parametersInput);

	panel2.add(parametersButton);
	parametersButton.addActionListener(this);

	configuration.doLayout();

	// //////////// SIMULATION \\\\\\\\\\\\\\\\\\\\\\\\\\\\
	simulation.setBackground(Color.WHITE);
	simulation.setSize(globalWidth, sizeSimulation);
	simulation.setLocation(2 * border, sizeConfiguartion + 3 * border + 2 * title);
	add(simulation);
	simulation.setLayout(null);

	resetButton.setLocation(240, 5);
	resetButton.setSize(60, 20);
	simulation.add(resetButton);
	resetButton.addActionListener(this);

	// SETTING OF THE LUGS
	List<Lug> nums = new ArrayList<Lug>();
	nums.add(Lug.One);
	nums.add(Lug.Zero);
	nums.add(Lug.Two);
	nums.add(Lug.Three);
	nums.add(Lug.Four);
	nums.add(Lug.Five);
	nums.add(Lug.Zero2);
	nums.add(Lug.Six);

	Label label = new Label("Drum: Lugs on bars");
	label.setLocation(10, 10);
	label.setSize(130, 20);
	simulation.add(label);

	drumSection.setLocation(10, 30);
	drumSection.setSize(300, 100);
	simulation.add(drumSection);
	Panel panel = new Panel();
	panel.setLayout(new GridLayout(27, 9, 2, 5));

	for (Bar bar : m209Bars.getBars()) {
	    lugsButtons.put(bar, new ArrayList<JButton>());

	    for (Lug lug : nums) {
		lugsButtons.get(bar).add(new JButton(lug.getId()));
	    }

	    for (JButton button : lugsButtons.get(bar)) {

		if (bar.getLug1().getId().equals(button.getText()) || bar.getLug2().getId().equals(button.getText())) {
		    button.setBackground(ACTIVE_BG);
		    button.setBorder(new LineBorder(M209Applet.ACTIVE_BG,2));
		} else {
		    button.setBackground(DEFAULT_BG);
		    button.setBorder(new LineBorder(Color.BLACK,1));
		}
		panel.add(button);
		button.addActionListener(this);
	    }
	    label=new Label("#"+String.format("%02d", bar.getId()));
	    label.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 9));
	    panel.add(label);
	}
	drumSection.add(panel);
	drumSection.doLayout();

	// COUNTER
	label = new Label("Counter");
	label.setLocation(220, 145);
	label.setSize(50, 20);
	simulation.add(label);
	counterInput.setLocation(270, 145);
	counterInput.setSize(30, 20);
	simulation.add(counterInput);
	counterInput.setEditable(false);
	counterInput.setText("C.");

	// SETTING OF THE PINS
	label = new Label("Wheels display");
	label.setLocation(10, 160);
	label.setSize(100, 20);
	simulation.add(label);
	wheelsSection.setLocation(10, 180);
	wheelsSection.setSize(300, 110);
	simulation.add(wheelsSection);
	panel = new Panel();

	panel.setLayout(new GridLayout(1, 6, 5, 0));

	ButtonWheel bb;
	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    keysButtons.put(wheel, new ArrayList<ButtonWheel>());

	    for (Key key : wheel.getKeys()) {
		bb = new ButtonWheel(wheel, key.name().charAt(0));
		keysButtons.get(wheel).add(bb);
		if (key == Key.B) {
		    switch (wheel.getId()) {
			case 1:
			    b1 = bb.getButton();
			    break;
			case 2:
			    b2 = bb.getButton();
			    break;
			case 3:
			    b3 = bb.getButton();
			    break;
			case 4:
			    b4 = bb.getButton();
			    break;
			case 5:
			    b5 = bb.getButton();
			    break;
			case 6:
			    b6 = bb.getButton();
			    break;
		    }
		}
	    }

	    for (ButtonWheel buttonWheel : keysButtons.get(wheel)) {
		buttonWheel.setPrevious(keysButtons.get(wheel).get((keysButtons.get(wheel).indexOf(buttonWheel) + 1) % keysButtons.get(wheel).size()));
	    }

	    panel2 = new Panel();
	    panel2.setLayout(new GridLayout(26, 1, 0, 5));
	    for (ButtonWheel button : keysButtons.get(wheel)) {
		if (wheel.getKeyPins().get(Key.charToKey(button.getKey()))) {
		    button.setBackground(ACTIVE_BG);
		    button.setEffective(true);
		} else {
		    button.setBackground(DEFAULT_BG);
		    button.setEffective(false);
		}
		panel2.add(button.getButton());
		button.getButton().addActionListener(this);
	    }
	    panel.add(panel2);
	}
	wheelsSection.add(panel);
	wheelsSection.doLayout();

	// ACTION BUTTONS
	goButton.setBounds(320, 30, 50, 260);
	simulation.add(goButton);
	goButton.addActionListener(this);

	// MODE BUTTON

	modeButton.setBounds(130, 145, 70, 20);
	simulation.add(modeButton);
	modeButton.addActionListener(this);

	simulation.doLayout();
	// //////////// INFORMATION \\\\\\\\\\\\\\\\\\\\\\\\\\\
	Panel back = new Panel(null);
	back.setBackground(Color.WHITE);
	back.setSize(globalWidth, sizeInformation);
	back.setLocation(2 * border, sizeConfiguartion + sizeSimulation + 4 * border + 3 * title);

	information.setBackground(Color.WHITE);
	int widthInformation = 150;
	information.setSize(widthInformation, sizeInformation);
	information.setLocation(2 * border + (globalWidth - widthInformation) / 2, sizeConfiguartion + sizeSimulation + 4 * border + 3 * title);
	information.setLayout(new GridLayout(3, 2));
	add(information);
	add(back);

	label = new Label("Visual key");
	information.add(label);
	information.add(externalKeyInput);
	externalKeyInput.setEditable(false);
	externalKeyInput.setFont(font);

	label = new Label("Active key");
	information.add(label);
	information.add(activeKeyInput);
	activeKeyInput.setEditable(false);
	activeKeyInput.setFont(font);

	// BEAUFORT SHIT KEY
	label = new Label("Beaufort key");
	information.add(label);
	information.add(beaufortShitKeyInput);
	beaufortShitKeyInput.setText("B.");
	beaufortShitKeyInput.setEditable(false);

	// BACKGROUND FOR BORDERS
	JPanel background = new JPanel(null);
	background.setBackground(Color.DARK_GRAY);
	background.setSize(globalWidth + 2 * border, sizeConfiguartion + sizeSimulation + sizeInformation + 3 * border + 3 * title);
	background.setLocation(border, border * 2);
	add(background);
	
	switchMode();
	reset();

    }

    private void setExternalKey() {
	// SET THE EXTERNAL KEY
	String externalKey = externalKeyInput.getText();
	char[] charArray = externalKey.toCharArray();
	for (int i = 0; i < 6; i++) {
	    m209wheels.getKeyWheels().get(i).setInitialPosition(Key.charToKey(charArray[i]));
	}

	JButton b = null;
	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    switch (wheel.getId()) {
		case 1:
		    b = b1;
		    break;
		case 2:
		    b = b2;
		    break;
		case 3:
		    b = b3;
		    break;
		case 4:
		    b = b4;
		    break;
		case 5:
		    b = b5;
		    break;
		case 6:
		    b = b6;
		    break;
	    }
	    while (b.getText().charAt(0) != wheel.getPosition().getKey()) {
		for (ButtonWheel buttonWheel : keysButtons.get(wheel)) {
		    buttonWheel.giveToNext();
		}
		for (ButtonWheel buttonWheel : keysButtons.get(wheel)) {
		    buttonWheel.actualize();
		}
	    }
	}
    }

    private void reset() {
	letterCounter = 0;
	shitCounter = 0;
	beaufortShitKeyInput.setText("");
	cipherTextInput.setText("");
	externalKeyInput.setText(intialKeyInput.getText());
	counterInput.setText("0");
	setExternalKey();
	visualisation();
    }

    private void switchMode() {
	isC = !isC;
	if (isC) {
	    goButton.setLabel("Encrypt");
	} else {
	    goButton.setLabel("Decrypt");
	}
    }

    private void visualisation() {
	// VISUALISATION OF THE ACTIVE KEY AND EXTERNAL KEY
	List<Integer> activeKeyPositions = new ArrayList<Integer>();
	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    for (ButtonWheel button : keysButtons.get(wheel)) {
		if (wheel.getActiveKey().getKey() == button.getKey()) {
		    button.setForeground(ACTIVE_FG);
		    button.setFont(fontActive);
		    button.setActiveKey(true);
		    if (button.getBackground() == ACTIVE_BG) {
			activeKeyPositions.add(wheel.getId());
		    }
		} else if (wheel.getPosition().getKey() == button.getKey()) {
		    button.setFont(fontActive);
		    button.setSeenKey(true);
		    button.setForeground(ACTIVE_FG2);
		} else {
		    button.setSeenKey(false);
		    button.setActiveKey(false);
		    button.setForeground(DEFAULT_FG);
		    button.setFont(fontDefault);
		}
	    }
	}

	// VISUALISATION OF THE POSITION
	for (Bar bar : m209Bars.getBars()) {
	    for (JButton button : lugsButtons.get(bar)) {
		if (button.getBackground() == ACTIVE_BG && activeKeyPositions.contains(Integer.decode(button.getText()))) {
		    button.setForeground(ACTIVE_FG);
		    button.setFont(fontActive);
		} else {
		    button.setForeground(DEFAULT_FG);
		    button.setFont(fontDefault);
		}
	    }
	}

	// PARAMETERS
	parametersInput.setText(m209Bars.toStringToSave() + m209wheels.toStringToSave());

	// ACTIVE KEY
	String newActiveKey = new StringBuilder().append(m209wheels.getKeyWheels().get(0).getActiveKey().getKey()).append(m209wheels.getKeyWheels().get(1).getActiveKey().getKey()).append(
		m209wheels.getKeyWheels().get(2).getActiveKey().getKey()).append(m209wheels.getKeyWheels().get(3).getActiveKey().getKey()).append(
		m209wheels.getKeyWheels().get(4).getActiveKey().getKey()).append(m209wheels.getKeyWheels().get(5).getActiveKey().getKey()).toString();
	activeKeyInput.setText(newActiveKey);
    }

    public void actionPerformed(ActionEvent event) {
	if (event.getSource() == intialKeyInput) {
	    externalKeyInput.setText(intialKeyInput.getText());
	    setExternalKey();

	}

	// COMPUTATION (ENCRYPTION)
	if (event.getSource() == goButton) {

	    setExternalKey();

	    // /ENCRYPTION

	    int beaufortShitKey = GetBeaufortKey.getResultingInt(m209Bars, m209wheels);
	    beaufortShitKeyInput.setText(new StringBuilder().append(beaufortShitKey).toString());

	    char plainChar;
	    String cipherLetter;
	    if (isC) {
		if (letterCounter < plainTextInput.getText().length()) {
		    plainChar = plainTextInput.getText().charAt(letterCounter);
		    
		    cipherLetter = Beaufort.getResultingLetterEncrypt(Key.charToKey(plainChar), beaufortShitKey).toString();
		} else {
		    //plainChar = 'Z';
		    plainTextInput.setText(plainTextInput.getText().concat("-"));
		    cipherLetter = "X";
		}
	    } else {// Decryption
		if (letterCounter + shitCounter < plainTextInput.getText().length()) {
		    if (plainTextInput.getText().charAt(letterCounter + shitCounter) == ' ') {
			shitCounter++;
		    }
		    plainChar = plainTextInput.getText().charAt(letterCounter + shitCounter);

		    cipherLetter = Beaufort.getResultingLetterEncrypt(Key.charToKey(plainChar), beaufortShitKey).toString();
		} else {
		    plainTextInput.setText(plainTextInput.getText().concat("-"));
		    cipherLetter = "X";
		}
	    }

	    String cipherResul;

	    if (letterCounter != 0 && letterCounter % 5 == 0 && isC) {
		cipherResul = cipherTextInput.getText().concat(" ").concat(cipherLetter);
		;
	    } else {// Decryption
		if(cipherLetter.equals("Z") && !isC){
		    cipherLetter=" ";
		}
		cipherResul = cipherTextInput.getText().concat(cipherLetter);
	    }
	    cipherTextInput.setText(cipherResul);

	    counterInput.setText(Integer.toString(letterCounter + 1));
	    // increment counter
	    letterCounter++;

	    // increment vector
	    for (KeyWheel wheel : m209wheels.getKeyWheels()) {
		wheel.setNextPosition();
	    }


	    String newExternalKey = new StringBuilder().append(m209wheels.getKeyWheels().get(0).getPosition().getKey()).append(m209wheels.getKeyWheels().get(1).getPosition().getKey()).append(
		    m209wheels.getKeyWheels().get(2).getPosition().getKey()).append(m209wheels.getKeyWheels().get(3).getPosition().getKey()).append(
		    m209wheels.getKeyWheels().get(4).getPosition().getKey()).append(m209wheels.getKeyWheels().get(5).getPosition().getKey()).toString();
	    externalKeyInput.setText(newExternalKey);

	}

	// SWITCH MODE
	if (event.getSource() == modeButton) {
	    switchMode();
	}

	// RESET
	if (event.getSource() == resetButton) {
	    reset();
	}

	// SETTING with TextArea
	if (event.getSource() == parametersButton) {
	    StringToSetting.stringToSetting(m209Bars, m209wheels, parametersInput.getText());
	}

	// SET THE PINS
	for (KeyWheel wheel : m209wheels.getKeyWheels()) {
	    for (ButtonWheel button : keysButtons.get(wheel)) {
		if (event.getSource() == button.getButton()) {
		    wheel.getKeyPins().put(Key.charToKey(button.getKey()), !wheel.getKeyPins().get(Key.charToKey(button.getKey())));
		    button.setEffective(!button.isEffective());
		}
		// if(button.isEffective()){
		if (wheel.getKeyPins().get(Key.charToKey(button.getKey()))) {
		    button.setBackground(ACTIVE_BG);
		    button.setEffective(true);
		} else {
		    button.setBackground(DEFAULT_BG);
		    button.setEffective(false);
		}
	    }
	}

	// SET THE LUGS
	for (Bar bar : m209Bars.getBars()) {
	    for (JButton button : lugsButtons.get(bar)) {
		if (event.getSource() == button) {
		    if (button.getBackground() == ACTIVE_BG) {
			if (bar.getLug1().getId().equals(button.getText())) {
			    bar.setLug1(Lug.Null);
			} else if (bar.getLug2().getId().equals(button.getText())) {
			    bar.setLug2(Lug.Null);
			} else {
			    // XXX error
			}
			button.setBackground(DEFAULT_BG);
			button.setBorder(new LineBorder(Color.BLACK,1));
		    } else if (button.getBackground() == DEFAULT_BG) {
			if (bar.getLug1() == Lug.Null) {
			    bar.setLug1(Lug.StringToLug(button.getText()));

			    button.setBackground(ACTIVE_BG);
			    button.setBorder(new LineBorder(M209Applet.ACTIVE_BG,2));
			} else if (bar.getLug2() == Lug.Null) {
			    bar.setLug2(Lug.StringToLug(button.getText()));

			    button.setBackground(ACTIVE_BG);
			    button.setBorder(new LineBorder(M209Applet.ACTIVE_BG,2));
			} else {
			    // XXX error
			}
		    } else {
			// XXX error

		    }
		} else {
		    if (bar.getLug1().getId().equals(button.getText()) || bar.getLug2().getId().equals(button.getText())) {
			button.setBackground(ACTIVE_BG);
			button.setBorder(new LineBorder(M209Applet.ACTIVE_BG,2));
		    } else {
			button.setBackground(DEFAULT_BG);
			button.setBorder(new LineBorder(Color.BLACK,1));
		    }
		}
	    }
	}

	visualisation();
    }
}
